//  gGA.java
//
//  Author:
//       Antonio J. Nebro <antonio@lcc.uma.es>
//       Juan J. Durillo <durillo@lcc.uma.es>
//
//  Copyright (c) 2011 Antonio J. Nebro, Juan J. Durillo
//
//  This program is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Lesser General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Lesser General Public License for more details.
// 
//  You should have received a copy of the GNU Lesser General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.

package jmetal.metaheuristics.singleObjective.island;

import java.util.Comparator;
import java.util.concurrent.Executor;

import jmetal.core.Algorithm;
import jmetal.core.Operator;
import jmetal.core.Problem;
import jmetal.core.Solution;
import jmetal.core.SolutionSet;
import jmetal.util.JMException;
import jmetal.util.comparators.ObjectiveComparator;

/**
 * Class implementing a generational genetic algorithm
 */
public class IslandLTGA extends Algorithm implements Runnable {
	private SolutionSet solutions;

	private SolutionSet outputSolutions;

	/**
	 * 
	 * Constructor Create a new GGA instance.
	 * 
	 * @param problem
	 *            Problem to solve.
	 */
	public IslandLTGA(Problem problem) {
		super(problem);
	} // GGA

	@Override
	public synchronized void run() {
		try {
			int populationSize;
			int maxEvaluations;
			int evaluations;

			SolutionSet population;
			SolutionSet offspringPopulation;

			Operator mutationOperator;
			Operator crossoverOperator;
			Operator selectionOperator;

			Comparator comparator;
			comparator = new ObjectiveComparator(0); // Single objective
														// comparator

			// Read the params
			populationSize = ((Integer) this.getInputParameter("populationSize")).intValue();
			maxEvaluations = ((Integer) this.getInputParameter("maxEvaluations")).intValue();

			// Initialize the variables
			population = solutions;
			offspringPopulation = new SolutionSet(populationSize);

			evaluations = 0;

			// Read the operators
			mutationOperator = this.operators_.get("mutation");
			crossoverOperator = this.operators_.get("crossover");
			selectionOperator = this.operators_.get("selection");

			// Sort population
			population.sort(comparator);
			while (evaluations < maxEvaluations) {
				offspringPopulation.add(new Solution(population.get(0)));
				offspringPopulation.add(new Solution(population.get(1)));

				// Reproductive cycle
				for (int i = 0; i < (populationSize / 2 - 1); i++) {
					// Selection
					Solution[] parents = new Solution[2];

					parents[0] = (Solution) selectionOperator.execute(population);
					parents[1] = (Solution) selectionOperator.execute(population);

					// Crossover
					Solution[] offspring = (Solution[]) crossoverOperator.execute(parents);

					// Mutation
					mutationOperator.execute(offspring[0]);
					mutationOperator.execute(offspring[1]);

					// Evaluation of the new individual
					problem_.evaluate(offspring[0]);
					problem_.evaluate(offspring[1]);

					evaluations += 2;
					IslandLTGAController.evaluationsTotal += 2;
					// Replacement: the two new individuals are inserted in the
					// offspring
					// population
					offspringPopulation.add(offspring[0]);
					offspringPopulation.add(offspring[1]);
				} // for

				// The offspring population becomes the new current population
				population.clear();
				for (int i = 0; i < populationSize; i++) {
					population.add(offspringPopulation.get(i));
				}
				offspringPopulation.clear();
				population.sort(comparator);
			} // while

			outputSolutions = population;

			notifyAll();
		} catch (JMException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Execute the GGA algorithm
	 * 
	 * @throws JMException
	 */
	public synchronized SolutionSet execute(SolutionSet solutions, Executor executor) throws JMException,
			ClassNotFoundException {
		this.solutions = solutions;
		executor.execute(this);

		while (outputSolutions == null
				|| outputSolutions.size() < ((Integer) this.getInputParameter("populationSize")).intValue()) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		return outputSolutions;
	}

	/**
	 * Execute the GGA algorithm
	 * 
	 * @throws JMException
	 */
	public SolutionSet execute() throws JMException, ClassNotFoundException {
		return null;
	}
}